package com.atguigu.exam.service.impl;


import ch.qos.logback.core.joran.conditional.IfAction;
import com.atguigu.exam.entity.*;
import com.atguigu.exam.mapper.*;
import com.atguigu.exam.service.PaperQuestionService;
import com.atguigu.exam.service.PaperService;
import com.atguigu.exam.vo.AiPaperVo;
import com.atguigu.exam.vo.PaperVo;
import com.atguigu.exam.vo.RuleVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;


/**
 * 试卷服务实现类
 */
@Slf4j
@Service
public class PaperServiceImpl extends ServiceImpl<PaperMapper, Paper> implements PaperService {

    @Autowired
    private PaperMapper paperMapper;

    @Autowired
    private PaperQuestionMapper paperQuestionMapper;

    @Autowired
    private QuestionMapper questionMapper;

    @Autowired
    private QuestionChoiceMapper questionChoiceMapper;

    @Autowired
    private QuestionAnswerMapper questionAnswerMapper;

    @Autowired
    private PaperQuestionService paperQuestionService;

    @Autowired
    private ExamRecordMapper examRecordMapper;

    // 获取带题目的试卷详情
    @Override
    public Paper queryPageDetailById(Long id) {

        // 1. 单表paper查询
        Paper paper = getById(id);
        // 2. 校验paper == null -> 抛异常
        if (paper == null) {
            throw new RuntimeException("指定id:%s 试卷已经被删除，无法查看详情！".formatted(id));
        }
        // 3. 根据paperId查询题目集合(中间，题目，答案，选项)
        List<Question> questionList = questionMapper.customQueryQuestionListByPaperId(id);
        // 4. 校验题目集合 == null ->
        if (ObjectUtils.isEmpty(questionList)) {
            paper.setQuestions(new ArrayList<Question>());
            log.warn("试卷中没有题目！可进行试卷编辑，但是不能用于考试！，对应试卷id：{}",id);
            return paper;
        }

        log.debug("题目信息排序前：{}",questionList);
        // 对题目进行排序 选择-判断-简答
        questionList.sort((o1,o2) -> Integer.compare(getTypeOrder(o1.getType()),getTypeOrder(o2.getType())));
        // type排序是字符类型
        log.debug("题目信息排序后：{}",questionList);

        // 进行paper题目集合赋值
        paper.setQuestions(questionList);
        return paper;
    }

    // 手动添加试卷
    @Override
    public Paper createPage(PaperVo paperVo) {
        // 1. 完善试卷内信息 名字 描述 时间 -> 状态 ，总题目书 ， 总分数
        Paper paper = new Paper();
        /*if (ObjectUtils.isEmpty(paper.getName())) {
            throw new RuntimeException("试卷名称不能为空！");
        }*/
        /*paper.setName(paperVo.getName());
        paper.setDescription(paperVo.getDescription());
        paper.setDuration(paperVo.getDuration());*/
        BeanUtils.copyProperties(paperVo,paper);
        paper.setStatus("DRAFT");
        if (ObjectUtils.isEmpty(paperVo.getQuestions())) {
            // 本次没选题目
            paper.setTotalScore(BigDecimal.ZERO);
            paper.setQuestionCount(0);
            save(paper);
            return paper;
        }
        paper.setQuestionCount(paperVo.getQuestions().size());
        paper.setTotalScore(paperVo.getQuestions().values().stream().reduce(BigDecimal.ZERO,BigDecimal::add));
        // 2. 完成试卷的插入
        save(paper);
        // 3. questions -> 中间表集合 （题目id，试卷id，分数）
        List<PaperQuestion> paperQuestionList = paperVo.getQuestions().entrySet().stream().
                map(entry -> new PaperQuestion(paper.getId().intValue(), Long.valueOf(entry.getKey()), entry.getValue()))
                .collect(Collectors.toList());
        // 4. 完成中间表的插入[批量插入]
        paperQuestionService.saveBatch(paperQuestionList);
        // 5. 返回对应paper对象
        return paper;
    }

    // AI智能组卷
    @Transactional
    @Override
    public Paper creatPaperWithAi(AiPaperVo aiPaperVo) {
        // 1. 创建并保存试卷基本信息
        Paper paper = new Paper();
        BeanUtils.copyProperties(aiPaperVo,paper);
        /*paper.setName(aiPaperVo.getName());
        paper.setDescription(aiPaperVo.getDescription());
        paper.setDuration(aiPaperVo.getDuration());*/
        paper.setStatus("DRAFT");
        save(paper);
        /*if (ObjectUtils.isEmpty(paper.getName())) {
            throw new RuntimeException("试卷名称不能为空！");
        }*/
        // 2. 根据规则抽取题目
        int questionCount = 0;
        //总分数（不能直接根据规则计算，同理）
        BigDecimal totalScore = BigDecimal.ZERO;
        for (RuleVo rule : aiPaperVo.getRules()) {
            // 步骤一：校验规则下的题目数量 = 0 跳过
            if (rule.getCount() == null || rule.getCount() == 0) {
                log.warn("在 {} 下，不需要出题", rule.getType().name());
                continue;
            }
            // 步骤二 查询当前题目下的所有规则集合
            LambdaQueryWrapper<Question> queryWrapper = new LambdaQueryWrapper<>();
            //题目类型 "CHOICE", "JUDGE", "TEXT"
            queryWrapper.eq(Question::getType, rule.getType().name());
            queryWrapper.in(!ObjectUtils.isEmpty(rule.getCategoryIds()), Question::getCategoryId, rule.getCategoryIds());
            List<Question> allQuestionList = questionMapper.selectList(queryWrapper);

            // 步骤三 校验查询的题目集合，集合为空跳过本次
            if (ObjectUtils.isEmpty(allQuestionList)) {
                log.warn("在 {} 类型下，我们指定的分类：{} ，没有查询到题目信息", rule.getType().name(), rule.getCategoryIds());
                continue;
            }

            // 步骤四: 判断你是否有规则下count数量
            int realNumbers = Math.min(rule.getCount(), allQuestionList.size());

            // 步骤五:本次规则下添加的数量和分数累加
            questionCount += realNumbers;
            totalScore = totalScore.add(BigDecimal.valueOf((long) realNumbers * rule.getScore()));

            // 步骤六：先打乱数据，在截取需要题目数量
            Collections.shuffle(allQuestionList);
            List<Question> realQuestionList = allQuestionList.subList(0, realNumbers);

            // 步骤七：转成中间表进行保存
            List<PaperQuestion> paperQuestionList = realQuestionList.stream().map(
                    question -> new PaperQuestion(paper.getId().intValue(), question.getId(), BigDecimal.valueOf(rule.getScore()))
            ).collect(Collectors.toList());
            paperQuestionService.saveBatch(paperQuestionList);
        }
        // 3. 修改试卷信息(总题数，总分数)
        paper.setQuestionCount(questionCount);
        paper.setTotalScore(totalScore);
        updateById(paper);
        return paper;

    }

    // 更新修改试卷
    @Override
    public Paper updatePaper(Integer id, PaperVo paperVo) {
        // 1. 校验状态是否为发布状态，发布状态不能更新抛出异常
        Paper paper = getById(id);
        /*if (ObjectUtils.isEmpty(paper.getName())) {
            throw new RuntimeException("试卷名称不能为空！");
        }*/
        if ("PUBLISHED".equals(paper.getStatus())) {
            throw new RuntimeException("发布状态之下的试卷不能修改！!");
        }
        // 校验id，name
        LambdaQueryWrapper<Paper> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.ne(Paper::getId,id);
        queryWrapper.eq(Paper::getName,paperVo.getName());
        long count = count(queryWrapper);
        if (count>0) {
            throw new RuntimeException("%s的试卷名字已经存在！");
        }
        // 2. 试卷的主体
        BeanUtils.copyProperties(paperVo,paper);
        paper.setQuestionCount(paperVo.getQuestions().size());
        paper.setTotalScore(paperVo.getQuestions().values().stream().reduce(BigDecimal.ZERO,BigDecimal::add));
        updateById(paper);

        // 3. 中间表的批量插入
        paperQuestionService.remove(new LambdaQueryWrapper<PaperQuestion>().eq(PaperQuestion::getPaperId,paper.getId()));
        List<PaperQuestion> paperQuestionList = paperVo.getQuestions().entrySet().stream()
                .map(entry -> new PaperQuestion(paper.getId().intValue(), Long.valueOf(entry.getKey()), entry.getValue())).collect(Collectors.toList());

        // 4.中间表的插入
        paperQuestionService.saveBatch(paperQuestionList);
        return paper;


    }

    // 修改试卷状态
    @Override
    public void updatePaperStatus(Integer id, String status) {
        // 1.判断目标状态 ->  发布  ->  查询试卷的试题数量
        if ("PUBLISHED".equals(status)){
            LambdaQueryWrapper<PaperQuestion> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(PaperQuestion::getPaperId,id);
            long count = paperQuestionService.count(lambdaQueryWrapper);
            if (count == 0){
                throw new RuntimeException("状态修改失败!目标为发布状态试卷必须有题目！");
            }
        }
        // 2. 正常修改状态即可
        LambdaUpdateWrapper<Paper> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.set(Paper::getStatus,status);
        lambdaUpdateWrapper.eq(Paper::getId, id);
        update(lambdaUpdateWrapper);

    }

    // 删除试卷接口
    @Override
    public void removePaper(Integer id) {
        // 1.不是发布状态
        Paper paper = getById(id);
        if (paper == null || "PUBLISHED".equals(paper.getStatus())) {
            throw new RuntimeException("发布状态的试卷不能删除！");
        }
        // 2.不能有关联的考试记录
        LambdaQueryWrapper<ExamRecord> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(ExamRecord::getExamId,id);
        Long count = examRecordMapper.selectCount(lambdaQueryWrapper);
        if (count > 0){
            throw new RuntimeException("当前试卷：%s 下面有关联 %s 条考试记录，无法直接删除！".formatted(id,count));
        }
        // 3. 删除自身表
        removeById(Long.valueOf(id));
        // 4. 删除中间表
        paperQuestionService.remove(new LambdaQueryWrapper<PaperQuestion>().eq(PaperQuestion::getPaperId,id));
    }

    /*------------------------------------------------------------------------------------*/
    /*------------------------------------------------------------------------------------*/
    /*------------------------------------------------------------------------------------*/
    /*------------------------------------------------------------------------------------*/
    /*------------------------------------------------------------------------------------*/
    /*------------------------------------------------------------------------------------*/
    /*------------------------------------------------------------------------------------*/
    /*------------------------------------------------------------------------------------*/
    /*------------------------------------------------------------------------------------*/
    /*------------------------------------------------------------------------------------*/
    /*------------------------------------------------------------------------------------*/
    /*------------------------------------------------------------------------------------*/
    /*------------------------------------------------------------------------------------*/
    /*------------------------------------------------------------------------------------*/
    /*------------------------------------------------------------------------------------*/
    /*------------------------------------------------------------------------------------*/
    /*------------------------------------------------------------------------------------*/
    /*------------------------------------------------------------------------------------*/
    /**
     * 获取题目类型的排序顺序
     * @param type 题目类型
     * @return 排序序号
     */
    private int getTypeOrder(String type) {
        switch (type) {
            // 选择题
            case "CHOICE": return 1;
            // 判断题
            case "JUDGE": return 2;
            // 简答题
            case "TEXT": return 3;
            // 其他类型
            default: return 4;
        }
    }

}